﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Controls.Primitives;

namespace Silverlight.ControlToolkit.Windows
{
    [TemplatePart(Name = WindowPanel.RootContainerElement, Type = typeof(Canvas))] //Canvas is required to implement drag & drop
    [TemplatePart(Name = WindowPanel.RootElement, Type = typeof(FrameworkElement))]
    [TemplatePart(Name = WindowPanel.HeaderElement, Type = typeof(FrameworkElement))]
    [TemplatePart(Name = WindowPanel.HeaderTextElement, Type = typeof(FrameworkElement))]
    [TemplatePart(Name = WindowPanel.ExpanderElement, Type = typeof(FrameworkElement))]
    [TemplatePart(Name = WindowPanel.CloseElement, Type = typeof(FrameworkElement))]
    [TemplatePart(Name = WindowPanel.ContentHolderElement, Type = typeof(FrameworkElement))]
    [TemplatePart(Name = WindowPanel.ExpandAnimationStoryboard, Type = typeof(Storyboard))]
    [TemplatePart(Name = WindowPanel.CollapseAnimationStoryboard, Type = typeof(Storyboard))]
    public class WindowPanel : ContentControl
    {

        private const string RootContainerElement = "RootContainerElement";
        private const string RootElement = "RootElement";
        private const string HeaderElement = "HeaderElement";
        private const string HeaderTextElement = "HeaderTextElement";
        private const string ExpanderElement = "ExpanderElement";
        private const string MinimizeElement = "MinimizeElement";
        private const string MaximizeElement = "MaximizeElement";
        private const string CloseElement = "CloseElement";
        private const string ContentElement = "ContentElement";
        private const string ContentHolderElement = "ContentHolderElement";
        private const string ExpandAnimationStoryboard = "ExpandAnimationStoryboard";
        private const string CollapseAnimationStoryboard = "CollapseAnimationStoryboard";

        private Canvas _rootContainerElement;
        internal FrameworkElement _rootElement;
        private FrameworkElement _headerElement;
        private FrameworkElement _headerTextElement;
        private FrameworkElement _expanderElement;
        private FrameworkElement _closeElement;
        internal FrameworkElement _contentHolderElement;
        private ContentPresenter _content;
        private Storyboard _expandAnimationStoryboard;
        private Storyboard _collapseAnimationStoryboard;

        public event RoutedEventHandler Expanded;
        public event RoutedEventHandler Collapsed;

        public event RoutedEventHandler Dragged;

        public event DialogBoxClosingEventHandler DialogBoxClosing;
        public event DialogBoxClosedEventHandler DialogBoxClosed;

        public WindowPanel()
            : base()
        {
            this.DefaultStyleKey = typeof(WindowPanel);
        }

        internal ModalDialog ModalDialogInstance { get; set; }

        public static readonly DependencyProperty IsExpandableProperty =
            DependencyProperty.Register("IsExpandable", typeof(bool), typeof(WindowPanel),
                                new PropertyMetadata(new PropertyChangedCallback(IsExpandableChangedCallback)));

        private static void IsExpandableChangedCallback(DependencyObject obj,
                                DependencyPropertyChangedEventArgs args)
        {
            if (obj != null && ((WindowPanel)obj)._contentHolderElement != null)
            {
                if (args.OldValue != null && ((bool)args.OldValue) && (((WindowPanel)obj)._headerElement != null))
                {
                    ((WindowPanel)obj)._headerElement.MouseLeftButtonDown -= new MouseButtonEventHandler(((WindowPanel)obj)._expandCollapseButton_MouseLeftButtonDown);
                    
                    if (((WindowPanel)obj)._expanderElement != null)
                        ((WindowPanel)obj)._expanderElement.Visibility = Visibility.Collapsed;

                }

                if (args.NewValue != null && ((bool)args.NewValue) && (((WindowPanel)obj)._headerElement != null))
                {

                    ((WindowPanel)obj)._headerElement.MouseLeftButtonDown += new MouseButtonEventHandler(((WindowPanel)obj)._expandCollapseButton_MouseLeftButtonDown);

                    if (((WindowPanel)obj)._expanderElement != null)
                        ((WindowPanel)obj)._expanderElement.Visibility = Visibility.Visible;
                
                }
            }
        }

        public bool IsExpandable
        {
            get
            {
                return (bool)GetValue(IsExpandableProperty);
            }

            set
            {
                SetValue(IsExpandableProperty, value);
            }
        }

        public static readonly DependencyProperty ShowCloseButtonProperty =
            DependencyProperty.Register("ShowCloseButton", typeof(bool), typeof(WindowPanel),
                                new PropertyMetadata(true, new PropertyChangedCallback(ShowCloseButtonChangedCallback)));

        private static void ShowCloseButtonChangedCallback(DependencyObject obj,
                                DependencyPropertyChangedEventArgs args)
        {
            if (obj != null && ((WindowPanel)obj)._headerElement != null)
            {
                if (args.OldValue != null && ((bool)args.OldValue) && (((WindowPanel)obj)._closeElement != null))
                {
                    if (((WindowPanel)obj)._closeElement is ButtonBase)
                        ((ButtonBase)((WindowPanel)obj)._closeElement).Click -= new RoutedEventHandler(((WindowPanel)obj)._closeElement_Click);
                    else
                        ((WindowPanel)obj)._closeElement.MouseLeftButtonUp -= new MouseButtonEventHandler(((WindowPanel)obj)._closeElement_MouseLeftButtonUp);
                    
                    ((WindowPanel)obj)._closeElement.Visibility = Visibility.Collapsed;

                }

                if (args.NewValue != null && ((bool)args.NewValue) && (((WindowPanel)obj)._closeElement != null))
                {
                    ((WindowPanel)obj)._closeElement.Visibility = Visibility.Visible;

                    if (((WindowPanel)obj)._closeElement is ButtonBase)
                        ((ButtonBase)((WindowPanel)obj)._closeElement).Click += new RoutedEventHandler(((WindowPanel)obj)._closeElement_Click);
                    else
                        ((WindowPanel)obj)._closeElement.MouseLeftButtonUp += new MouseButtonEventHandler(((WindowPanel)obj)._closeElement_MouseLeftButtonUp);
                }
            }
        }

        public bool ShowCloseButton
        {
            get
            {
                return (bool)GetValue(ShowCloseButtonProperty);
            }

            set
            {
                SetValue(ShowCloseButtonProperty, value);
            }
        }

        public static readonly DependencyProperty IsDraggableProperty =
            DependencyProperty.Register("IsDraggable", typeof(bool), typeof(WindowPanel),
                                new PropertyMetadata(true, new PropertyChangedCallback(IsDraggableChangedCallback)));

        private static void IsDraggableChangedCallback(DependencyObject obj,
                                DependencyPropertyChangedEventArgs args)
        {
            if (obj != null && ((WindowPanel)obj)._headerElement != null)
            {
                if (args.OldValue != null && ((bool)args.OldValue) && (((WindowPanel)obj)._headerElement != null))
                {
                    ((WindowPanel)obj)._headerElement.MouseLeftButtonDown -= new MouseButtonEventHandler(((WindowPanel)obj)._headerElement_MouseLeftButtonDown);

                }

                if (args.NewValue != null && ((bool)args.NewValue) && (((WindowPanel)obj)._headerElement != null))
                {

                    ((WindowPanel)obj)._headerElement.MouseLeftButtonDown += new MouseButtonEventHandler(((WindowPanel)obj)._headerElement_MouseLeftButtonDown);

                }
            }
        }

        public bool IsDraggable
        {
            get
            {
                return (bool)GetValue(IsDraggableProperty);
            }

            set
            {
                SetValue(IsDraggableProperty, value);
            }
        }


        public static readonly DependencyProperty IsExpandedOnLoadProperty =
            DependencyProperty.Register("IsExpandedOnLoad", typeof(bool), typeof(WindowPanel),
                                new PropertyMetadata(new PropertyChangedCallback(IsExpandedOnLoadChangedCallback)));

        private static void IsExpandedOnLoadChangedCallback(DependencyObject obj,
                                DependencyPropertyChangedEventArgs args)
        {
            if (obj != null && ((WindowPanel)obj)._contentHolderElement != null && ((bool)args.NewValue) != (((WindowPanel)obj)._contentHolderElement.Visibility == Visibility.Visible))
                ((WindowPanel)obj).ToggleView();
        }

        public bool IsExpandedOnLoad
        {
            get
            {
                return (bool)GetValue(IsExpandedOnLoadProperty);
            }

            set
            {
                SetValue(IsExpandedOnLoadProperty, value);
            }
        }


        public static readonly DependencyProperty HeaderTextProperty =
            DependencyProperty.Register("HeaderText", typeof(string), typeof(WindowPanel),
                                new PropertyMetadata(new PropertyChangedCallback(HeaderTextChangedCallback)));

        private static void HeaderTextChangedCallback(DependencyObject obj,
                                DependencyPropertyChangedEventArgs args)
        {
            if (obj != null && ((WindowPanel)obj)._headerTextElement != null)
                ((WindowPanel)obj)._headerTextElement.SetValue(TextBlock.TextProperty, args.NewValue);
        }

        public string HeaderText
        {
            get
            {
                return (string)GetValue(HeaderTextProperty);
            }

            set
            {
                SetValue(HeaderTextProperty, value);
            }
        }


        public static readonly DependencyProperty HeaderForegroundProperty =
            DependencyProperty.Register("HeaderForeground", typeof(Brush), typeof(WindowPanel),
                                new PropertyMetadata(new PropertyChangedCallback(HeaderForegroundChangedCallback)));

        private static void HeaderForegroundChangedCallback(DependencyObject obj,
                                DependencyPropertyChangedEventArgs args)
        {
            if (obj != null && ((WindowPanel)obj)._headerTextElement != null)
                ((WindowPanel)obj)._headerTextElement.SetValue(TextBlock.ForegroundProperty, args.NewValue);
        }

        public Brush HeaderForeground
        {
            get
            {
                return (Brush)GetValue(HeaderForegroundProperty);
            }

            set
            {
                SetValue(HeaderForegroundProperty, value);
            }
        }


        public static readonly DependencyProperty HeaderBackgroundProperty =
            DependencyProperty.Register("HeaderBackground", typeof(Brush), typeof(WindowPanel),
                                new PropertyMetadata(new PropertyChangedCallback(HeaderBackgroundChangedCallback)));

        private static void HeaderBackgroundChangedCallback(DependencyObject obj,
                                DependencyPropertyChangedEventArgs args)
        {
            if (obj != null && ((WindowPanel)obj)._headerElement != null)
                ((WindowPanel)obj)._headerElement.SetValue(Border.BackgroundProperty, args.NewValue);
        }

        public Brush HeaderBackground
        {
            get
            {
                return (Brush)GetValue(HeaderBackgroundProperty);
            }

            set
            {
                SetValue(HeaderBackgroundProperty, value);
            }
        }


        public static readonly DependencyProperty HeaderFontSizeProperty =
            DependencyProperty.Register("HeaderFontSize", typeof(double), typeof(WindowPanel),
                                new PropertyMetadata(new PropertyChangedCallback(HeaderFontSizeChangedCallback)));

        private static void HeaderFontSizeChangedCallback(DependencyObject obj,
                                DependencyPropertyChangedEventArgs args)
        {
            if (obj != null && ((WindowPanel)obj)._headerTextElement != null)
                ((WindowPanel)obj)._headerTextElement.SetValue(TextBlock.FontSizeProperty, args.NewValue);
        }

        public double HeaderFontSize
        {
            get
            {
                return (double)GetValue(HeaderFontSizeProperty);
            }

            set
            {
                SetValue(HeaderFontSizeProperty, value);
            }
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            _rootContainerElement = GetTemplateChild(WindowPanel.RootContainerElement) as Canvas;

            _rootElement = (FrameworkElement)GetTemplateChild(WindowPanel.RootElement);
            _headerElement = (FrameworkElement)GetTemplateChild(WindowPanel.HeaderElement);
            _headerTextElement = (FrameworkElement)GetTemplateChild(WindowPanel.HeaderTextElement);
            _expanderElement = (FrameworkElement)GetTemplateChild(WindowPanel.ExpanderElement);
            _closeElement = (FrameworkElement)GetTemplateChild(WindowPanel.CloseElement);
            
            _contentHolderElement = (FrameworkElement)GetTemplateChild(WindowPanel.ContentHolderElement);
            _content = (ContentPresenter)GetTemplateChild(WindowPanel.ContentElement);

            _expandAnimationStoryboard = (Storyboard)GetTemplateChild(WindowPanel.ExpandAnimationStoryboard);
            _collapseAnimationStoryboard = (Storyboard)GetTemplateChild(WindowPanel.CollapseAnimationStoryboard);


            if (_rootContainerElement != null && _rootElement != null)
                _rootElement.SizeChanged += new SizeChangedEventHandler(_rootElement_SizeChanged);

            if (_headerElement != null)
            {
                if (this.HeaderBackground != null)
                    _headerElement.SetValue(Border.BackgroundProperty, this.HeaderBackground);

                if (IsDraggable)
                    _headerElement.MouseLeftButtonDown += new MouseButtonEventHandler(_headerElement_MouseLeftButtonDown);


            }

            if (_expanderElement != null)
            {
                if (IsExpandable)
                {
                    _expanderElement.Visibility = Visibility.Visible;

                    if (_headerElement != null)
                        _headerElement.MouseLeftButtonDown += new MouseButtonEventHandler(_expandCollapseButton_MouseLeftButtonDown);

                }
                else
                    _expanderElement.Visibility = Visibility.Collapsed;
            }

            if (_closeElement != null)
            {
                if (ShowCloseButton)
                {
                    _closeElement.Visibility = Visibility.Visible;

                    if (_closeElement is ButtonBase)
                        ((ButtonBase)_closeElement).Click += new RoutedEventHandler(_closeElement_Click);
                    else
                        _closeElement.MouseLeftButtonUp += new MouseButtonEventHandler(_closeElement_MouseLeftButtonUp);
                }
                else
                    _closeElement.Visibility = Visibility.Collapsed;
            }


            if (_headerTextElement != null)
            {
                if (this.HeaderText != null)
                    _headerTextElement.SetValue(TextBlock.TextProperty, this.HeaderText);

                if (this.HeaderForeground != null)
                    _headerTextElement.SetValue(TextBlock.ForegroundProperty, this.HeaderForeground);


                if (this.HeaderFontSize > 0)
                    _headerTextElement.SetValue(TextBlock.FontSizeProperty, this.HeaderFontSize);

            }

            if (_contentHolderElement != null && this.IsExpandedOnLoad)
                this.ToggleView();


            //if (_rootElement != null)
            //{
            //    _enter = (Storyboard)_rootElement.Resources[WindowPanel.MouseEnterAnimation];
            //    _leave = (Storyboard)_rootElement.Resources[WindowPanel.MouseLeaveAnimation];
            //}
        }

        void _rootElement_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            _rootContainerElement.Width = e.NewSize.Width;
            _rootContainerElement.Height = e.NewSize.Height;
        }


        void _closeElement_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }

        void _closeElement_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            this.Close();
        }

        public void Close()
        {
            DialogBoxClosingEventArgs e = new DialogBoxClosingEventArgs();
            this.OnDialogBoxClosing(e);

            if (e.Cancel)
                return; //client has cacelled the close operation

            if (ModalDialogInstance == null)
            {
                if (this.Parent is Panel)
                    ((Panel)this.Parent).Children.Remove(this);
                else
                    this.Visibility = Visibility.Collapsed;
            }
            else //If this window is opened modally, close all the modal instances too
                ModalDialogInstance.Close(DialogResult.None);

            this.OnDialogBoxClosed();

        }

        protected virtual void OnDialogBoxClosing(DialogBoxClosingEventArgs e)
        {
            DialogBoxClosingEventHandler DialogBoxClosingEvent = this.DialogBoxClosing;

            if (DialogBoxClosingEvent != null)
            {
                e.Cancel = false;
                DialogBoxClosingEvent(this, e);
            }
        }

        /// <summary>
        /// Called when [dialog box closed].
        /// </summary>
        /// <param name="actionTaken">The action taken.</param>
        protected virtual void OnDialogBoxClosed()
        {
            DialogBoxClosedEventHandler DialogBoxClosedEvent = this.DialogBoxClosed;

            if (DialogBoxClosedEvent != null)
            {
                DialogBoxEventArgs e = new DialogBoxEventArgs();
                DialogBoxClosedEvent(this, e);
            }
        }

        Point _startingDragPoint;
        void _headerElement_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {

            if (!(_rootElement.Parent is Canvas)) //If not canvas then return
                return;

            //start Dragging
            _headerElement.CaptureMouse();

            // set the starting point for the drag
            _startingDragPoint = e.GetPosition(_headerElement);

            _headerElement.MouseMove += new MouseEventHandler(_headerElement_MouseMove);
            _headerElement.MouseLeftButtonUp += new MouseButtonEventHandler(_headerElement_MouseLeftButtonUp);

            this.Opacity = 0.5;


        }

        void _headerElement_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            //Stop Dragging
            _headerElement.ReleaseMouseCapture();

            _headerElement.MouseMove -= new MouseEventHandler(_headerElement_MouseMove);
            _headerElement.MouseLeftButtonUp -= new MouseButtonEventHandler(_headerElement_MouseLeftButtonUp);

            this.Opacity = 1;
        
        }

        void _headerElement_MouseMove(object sender, MouseEventArgs e)
        {
            Point position = e.GetPosition(_rootElement.Parent as FrameworkElement);

            Canvas.SetLeft(this._rootElement, position.X - _startingDragPoint.X);
            Canvas.SetTop(this._rootElement, position.Y - _startingDragPoint.Y);

            if (Dragged != null)
                Dragged(this, new RoutedEventArgs());

        }


        void _expandCollapseButton_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            this.ToggleView();
        }

        public void Expand()
        {
            if (this._contentHolderElement.Visibility == Visibility.Collapsed)
                this.ToggleView();
        }

        public void Collapse()
        {
            if (this._contentHolderElement.Visibility == Visibility.Visible)
                this.ToggleView();
        }

        private void ToggleView()
        {
            if (this._contentHolderElement.Visibility == Visibility.Collapsed)
            {
                this._contentHolderElement.Visibility = Visibility.Visible;

                if (Expanded != null)
                    Expanded(this, new RoutedEventArgs());

                if (this._expandAnimationStoryboard != null)
                    this._expandAnimationStoryboard.Begin();

            }
            else
            {
                this._contentHolderElement.Visibility = Visibility.Collapsed;

                if (Collapsed != null)
                    Collapsed(this, new RoutedEventArgs());

                if (this._collapseAnimationStoryboard != null)
                    this._collapseAnimationStoryboard.Begin();

            }
        }




    }
}
